package com.argesone.third.shanxiyingji.loginadapter.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.argesone.third.shanxiyingji.loginadapter.config.TowerLoginConfig;
import com.argesone.third.shanxiyingji.loginadapter.entity.User;
import com.argesone.third.shanxiyingji.loginadapter.service.IAuthService;
import com.argesone.third.shanxiyingji.loginadapter.utils.AesUtil;
import com.argesone.third.shanxiyingji.loginadapter.utils.HmacSHA1Util;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * 认证服务层接口实现类
 * </p>
 *
 * @author fanweitao
 * @since 2025-10-21
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements IAuthService {

    private final TowerLoginConfig towerConfig;

    /**
     * 获取铁塔门户登录地址
     *
     * @param userInfo 用户信息
     */
    @Override
    public String getTowerPortalLoginUrl(User userInfo) {
        try {
            // 校验用户信息
            String userCode = userInfo.getId();
            if (Objects.isNull(userInfo) || StringUtils.isBlank(userCode)) {
                throw new RuntimeException("user info is null.");
            }
            // 获取签名内容
            String servicePath = "/video/third/doPortalLogin";
            String msgId = IdUtil.fastSimpleUUID();
            String requestTime = LocalDateTime.now().format(DatePattern.NORM_DATETIME_FORMATTER);
            String signContext = getSignContext(servicePath, towerConfig.getAppKey(), msgId, requestTime, towerConfig.getCustomer(), userCode);
            String sign = sign(towerConfig.getSecretKey(), signContext);
            log.info("sign: " + sign);

            String password = userInfo.getPassword();
            try {
                password = SecureUtil.aes(towerConfig.getPasswordSecretKey().getBytes()).decryptStr(password);
            }catch (Exception e){
                password = towerConfig.getPassword();
            }
            log.info("current password is {} !",password);
            String passwordEnc = encSign(towerConfig.getSecretKey(), password);
            // 封装请求头参数
            Map<String, String> headerMap = MapUtil.builder(new HashMap<String, String>())
                    .put("X-AppKey", towerConfig.getAppKey())
                    .put("X-Signature", sign)
                    .put("X-MsgId", msgId)
                    .put("X-RequestTime", requestTime)
                    .put("X-CustomerCode", towerConfig.getCustomer())
                    .put("X-UserCode", userCode)
                    .put("X-AppCode", towerConfig.getAppCode())
                    .put("X-PassWord", passwordEnc)
                    .put("X-ServerCode", "doPortalLogin")
                    .build();
            // 获取接口地址
            String url = towerConfig.getUrl() + "/api/admin/video/third/doPortalLogin";
            log.info("-->> post url: {}", url);
            log.info("-->> headers: {}", JSONUtil.toJsonStr(headerMap));
            HttpResponse response = HttpUtil.createPost(url).addHeaders(headerMap).execute();
            log.info("-->> response status: " + response.getStatus());
            log.info("-->> response body: " + response.body());
            // 解析响应内容获取登录地址
            JSONObject body = JSONUtil.parseObj(response.body());
            if ("0000".equals(body.getStr("returnCode"))) {
                return body.getStr("data");
            }
        } catch (Exception e) {
            log.error("--->>> doPortalLogin error. errorMsg: {}", e.getMessage(), e);
        }
        // 默认返回铁塔门户首页
        return "/";
    }

    /**
     * 处理铁塔门户登录地址
     *
     * @param loginUrl 登录地址
     */
    public String disposeLoginUrl(String loginUrl) {
        // 处理地址为外网
        if (towerConfig.getNetworkMode() == 1) {
            String[] ss = loginUrl.split("uuid=");
            if (ss.length != 2) {
                log.warn("-->> split length != 2 ");
                return loginUrl;
            }
            String uuid = ss[1];
            return towerConfig.getUrl() + "/login?uuid=" + uuid;
        }
        return loginUrl;
    }

    /**
     * 密码签名
     *
     * @param sk       sk
     * @param password 密码
     * @return {@link String}
     */
    private static String encSign(String sk, String password) {
        // 从sk中截取前16个字符作为密钥
        String key = sk.substring(0, 16);
        // 将密钥转换为字节数组，并进一步转换为十六进制字符串
        String cipher = AesUtil.parseByte2HexStr(key.getBytes());
        try {
            // 使用AES算法对密码进行加密，并返回Base64编码后的字符串
            return AesUtil.encryptBase64(password, cipher);
        } catch (Exception e) {
            // 捕获并记录加密过程中可能出现的异常信息
            log.error("--->>> encSign error. errorMsg: {}", e.getMessage(), e);
            // 返回空字符串以示错误
            return "";
        }
    }


    /**
     * 签名
     *
     * @param secret      密钥
     * @param signContext 签名内容
     * @return {@link String}
     */
    public static String sign(final String secret, final String signContext) {
        // 使用HmacSHA1Util工具类的encode方法对签名内容进行编码，返回签名后的字符串
        return HmacSHA1Util.encode(signContext, secret);
    }


    /**
     * 根据请求参数拼接签名上下文字符串。
     * 该方法按照指定规则将多个参数按顺序拼接成一个字符串，用于后续的签名计算（如 MD5、HMAC 等）。
     *
     * @param path         请求路径（如 /api/login），不包含域名和查询参数
     * @param appKey       应用唯一标识（App Key），由平台分配
     * @param msgId        消息 ID，用于去重或追踪请求
     * @param requestTime  请求时间戳（通常为毫秒级时间戳）
     * @param customerCode 客户编号（Customer Code），平台客户唯一标识
     * @param userCode     用户编码（User Code），当前操作用户的唯一标识
     * @return 拼接后的签名上下文字符串，格式：path+appKey+msgId+requestTime+customerCode+userCode
     */
    private static String getSignContext(String path, String appKey, String msgId, String requestTime,
                                         String customerCode, String userCode) {
        StringBuilder append = new StringBuilder(path)
                .append(appKey)
                .append(msgId)
                .append(requestTime);
        // 如果客户编码不为空，则追加到拼接字符串中
        if (customerCode != null) {
            append.append(customerCode);
        }
        // 如果用户编码不为空，则追加到拼接字符串中
        if (userCode != null) {
            append.append(userCode);
        }
        log.info("oriSignContext: {}", append);
        return append.toString().toUpperCase();
    }

}
